﻿using System;
using Mjolnir.InfraEstrutura.Servicos;

namespace Mjolnir.Modelo.Matrizes
{
  public class ServicoMatriz : ServicoBase<Matriz, FabricaMatriz>, IServicoMatriz
  {
    //public void setarValor(Matriz valor)
    //{
    //  
    //}
    //public void obterValor(ref double[,] valor)
    //{
    //  
    //}
    public Matriz[] criarArray(int linhas, int colunas, int tamanho)
    {
      Matriz[] retorno = fabrica.criar(linhas, colunas, tamanho);
      
      return retorno;
    }

    public void setarValor(double[,] valor)
    {
      entidade.Valor = valor;
    }

    public void setarValor(Matriz valor)
    {
      entidade.Valor = valor.Valor;
    }

    public void obterValor(ref double[,] valor)
    {
      valor = entidade.Valor;
    }

    public bool inverso(Matriz fonte)
    {
      double[,] valor = new double[fonte.Linhas, fonte.Colunas];

      for (int l = 0; l < fonte.Linhas; l++)
      {
        for (int c = 0; c < fonte.Colunas; c++)
        {
          valor[l, c] = fonte.Valor[l, c];
        }
      }

      double determinante = 0;
      double calculo = 0;

      for (int l = 0; l < fonte.Linhas; l++)
      {
        for (int c = 0; c < fonte.Colunas; c++)
        {
          if (c == 0)
          {
            calculo = this.retorna(fonte, c, c + l);
          }
          else
          {
            calculo *= this.retorna(fonte, c, c + l);
          }
        }

        determinante += calculo;
        calculo = 0;

        if (fonte.Linhas == 2)
        {
          break;
        }
      }

      calculo = 0;

      for (int l = fonte.Linhas - 1; l >= 0; l--)
      {
        for (int c = 0; c < fonte.Colunas; c++)
        {
          if (c == 0)
          {
            calculo = this.retorna(fonte, c, (c - l) * -1, true);
          }
          else
          {
            calculo *= this.retorna(fonte, c, (c - l) * -1, true);
          }
        }

        determinante -= calculo;
        calculo = 0;

        if (fonte.Linhas == 2)
        {
          break;
        }
      }

      //1.1 x 2.2 x 3.3
      //       +
      //2.1 x 3.2 x 1.3
      //       +
      //3.1 x 1.2 x 2.3
      //       -
      //3.1 x 2.2 x 1.3
      //       -
      //3.2 x 2.3 x 1.1
      //       -
      //3.3 x 2.1 x 1.2
      return false;
    }

    private double retorna(Matriz fonte, int coluna, int linha, bool invertido = false)
    {
      if (invertido == false)
      {
        if (coluna >= fonte.Colunas)
        {
          coluna -= fonte.Colunas;
        }

        if (linha >= fonte.Linhas)
        {
          linha -= fonte.Linhas;
        }
      }
      else
      {
        if (coluna < 0)
        {
          coluna += fonte.Colunas;
        }

        if (linha < 0)
        {
          linha += fonte.Linhas;
        }
      }

      return fonte.Valor[linha, coluna];
    }
  }
}
